﻿#include "data.h"
//Data::Data(QObject *parent) : QObject(parent) {}

// Map::Map()
// {
//     block={{0}};
// }

Map::Map() : size(10, 10), start(0, 0), end(9, 9),
//    node(size.y,QVector<Node *>(size.x,nullptr)),
    outputData(size.y,QVector<OutputData *>(size.x,nullptr))
{
    block = {{0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 0, 1, 1, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 1, 1, 0, 1, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 1, 1, 1, 1, 1, 0}, {0, 1, 0, 0, 1, 0, 1, 1, 1, 0}, {0, 0, 0, 1, 1, 0, 0, 0, 1, 0}, {0, 1, 0, 0, 0, 0, 1, 0, 1, 0}, {0, 1, 1, 1, 0, 1, 1, 0, 1, 1}, {0, 0, 0, 0, 0, 0, 1, 0, 0, 0}};
//    node = {{nullptr}};
//    outputData = {{nullptr}};
    connect(this,&Map::map_output,this,&Map::mapChanged);
}

Map::Map(Point size) : size(size.x, size.y), start(0, 0), end(size.x-1, size.y-1),
//    node(size.y,QVector<Node *>(size.x,nullptr)),
    block(size.y,QVector<bool>(size.x,CLEAR)),
    outputData(size.y,QVector<OutputData *>(size.x,nullptr))
{
    connect(this,&Map::map_output,this,&Map::mapChanged);
}

Map::~Map()
{
    clearData();
}

Point Map::Size() const { return size; }

int Map::X() const { return size.x; }

int Map::Y() const { return size.y; }

bool Map::isOutOfRange(Point p)const
{
    return p.x>=size.x||p.y>=size.y
            ||p.x<0||p.y<0;
}

void Map::setStart(Point p)
{
    if (p == end)
    {
        swap();
        return;
    }
    auto s = start;
    start = p;
    emit mapChanged(s);
    block[p.y][p.x] = CLEAR;
    emit mapChanged(p);
}

void Map::setEnd(Point p)
{
    if (p == start)
    {
        swap();
        return;
    }
    auto s = end;
    end = p;
    emit mapChanged(s);
    block[p.y][p.x] = CLEAR;
    emit mapChanged(p);
}

void Map::swap()
{
    auto t = start;
    start = end;
    emit mapChanged(start);
    end = t;
    emit mapChanged(end);
}

void Map::setBlock(Point p, bool set)
{
    block[p.y][p.x] = set;
    emit mapChanged(p);
    qDebug() << "Block Changed"<<p.x<<","<<p.y;
    if (p == start)
    {
        start = {-1, -1};
    }
    else if (p == end)
    {
        end = {-1, -1};
    }
}

void Map::set(Point p, int state)
{
    switch (state)
    {
    case CLEAR:
    case BLOCK:
        setBlock(p, state);
        break;
    case START:
        setStart(p);
        break;
    case END:
        setEnd(p);
        break;
    default:
        break;
    }
}

bool Map::isBlock(Point p) const {
    return isOutOfRange(p)|| block.at(p.y).at(p.x);
}

int Map::is(Point p) const
{
    if (isBlock(p))
    {
        return BLOCK;
    }
    else
    {
        if (auto o=getOutput(p))
        {
            return o->flag;
        }
        if (p == start)
        {
            return START;
        }
        if (p == end)
        {
            return END;
        }
        return CLEAR;
    }
}

Point Map::getStart() const
{
    return start;
}

Point Map::getEnd() const
{
    return end;
}

void Map::output(Point p,Point pre,int flag,QString str)
{
    if(isOutOfRange(p))
    {
        qDebug()<<"Index out of range";
        return;
    }
    if (outputData.at(p.y).at(p.x))
    {
        delete outputData.at(p.y).at(p.x);
    }
    outputData[p.y][p.x]=new OutputData(pre,flag,str);
    emit map_output(p);
    qDebug() << "map_output"<<"坐标:("<<p.x<<","<<p.y<<")"
                <<"前驱坐标:("<<pre.x<<","<<pre.y<<")"
               <<"flag:"<<flag<<";"<<str;
}

void Map::clearOutputData(Point p) 
{
    if (outputData.at(p.y).at(p.x))
    {
        delete outputData.at(p.y).at(p.x);
        outputData[p.y][p.x]=nullptr;
    }
}

OutputData* Map::getOutput(Point p) const
{
    return outputData.at(p.y).at(p.x);
}

bool Map::isOutput(Point p) const
{
    auto o=getOutput(p);
    if(o){
        return 1;
    }else{
        return 0;
    }
}

QString Map::getText(Point p) const
{

    auto o=getOutput(p);
    if(o){
        return o->getText();
    }else{
        return "";
    }
}

int Map::getFlag(Point p) const
{
    auto o=getOutput(p);
    if(o){
        return o->getFlag();
    }else{
        return 0;
    }
}

int Map::getPreInt(Point p) const
{
    auto o=getOutput(p);
    if(o){
        auto op=o->getPre();
        if(op==Point(-1,-1)){
            return 0;
        }
        auto pr=op-p;
        int r=(pr.x+2)+(pr.y+1)*3;
        if(r>0&&r<10&&r!=5){
            return r;
        }else{
            return 0;
        }
    }else{
        return 0;
    }
}


//Point Map::getPre(Point p)
//{
//    return getOutput(p)->getPre()-p;
//}

//int Map::getPreInt(Point p)
//{
//    return (p.x+2)+(p.y+1)*3;
//}


//bool Map::isNode(Point p) const
//{
//    return node.at(p.y).at(p.x)!=nullptr;
//}

//Node *Map::getNode(Point p) const
//{
//    return node.at(p.y).at(p.x);
//}

void Map::clearData()
{
//    for (int i = 0; i < node.size(); ++i)
//    {
//        auto &n = node.at(i);
//        for (int ii = 0; ii < n.size(); ++ii)
//        {
//            auto &nn = n.at(ii);
//            if (nn) delete nn;
//            node[i][ii]=nullptr;
//        }
//    }
    for (int i = 0; i < outputData.size(); ++i)
    {
        auto &n = outputData.at(i);
        for (int ii = 0; ii < n.size(); ++ii)
        {
            auto &nn = n.at(ii);
            if (nn) delete nn;
            outputData[i][ii]=nullptr;
        }
    }
}


bool Point::operator==(const Point &p) const
{ return x == p.x && y == p.y; }

Point Point::operator+(const Point &p) const
{
    return Point(x+p.x,y+p.y);
}

Point Point::operator-(const Point &p) const
{
    return Point(x-p.x,y-p.y);
}

OutputData::OutputData(/*Point coordinate,*/Point pre0,int flag0,QString str0="")
:pre(pre0),flag(flag0),str(str0)
{
    ;
}

Point OutputData::getPre()
{
    return pre;
}

int OutputData::getFlag()
{
    return flag;
}

const QString& OutputData::getText()
{
    return str;
}

//Point::Point(const QModelIndex &index) { Point(index.row(), index.column()); }
